
package com.biz.primus.ms.commodity.service.backend;


import com.biz.primus.base.enums.commodity.IStatus;
import com.biz.primus.base.exception.utils.AssertUtils;
import com.biz.primus.base.vo.IdNameVo;
import com.biz.primus.commodity.exception.CommodityExceptionType;
import com.biz.primus.commodity.vo.BrandQueryVo;
import com.biz.primus.commodity.vo.SyncBrandVo;
import com.biz.primus.commodity.vo.backend.*;
import com.biz.primus.common.utils.CopyUtils;
import com.biz.primus.common.vo.SpringPageVO;
import com.biz.primus.ms.base.vo.SpringPageToSpringPageVO;
import com.biz.primus.ms.commodity.dao.po.Brand;
import com.biz.primus.ms.commodity.dao.po.Category;
import com.biz.primus.ms.commodity.dao.redis.BrandRedisDao;
import com.biz.primus.ms.commodity.dao.repository.category.CategoryRepository;
import com.biz.primus.ms.commodity.dao.ro.BrandRo;
import com.biz.primus.ms.commodity.dao.specification.BrandSpecification;
import com.biz.primus.ms.commodity.feign.VendorFeignClient;
import com.biz.primus.ms.commodity.trans.Brand2BrandListItemVo;
import com.biz.primus.ms.commodity.trans.Brand2BrandRo;
import com.biz.primus.ms.commodity.trans.Brand2IdNameVo;
import com.biz.primus.ms.commodity.trans.Brand2UpdateBrandVo;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 品牌 ServiceImpl
 *
 * @author 江南
 * @usage
 * @reviewer
 * @since 2016/12/19
 */
@Slf4j
@Service
public class BrandService extends AbstractBrandService {

    @Autowired
    private CategoryRepository categoryRepository;

    @Autowired
    private VendorFeignClient brandVendorRelationRepository;

    @Autowired
    private BrandRedisDao brandRedisDao;

    @Autowired
    private CategoryService categoryService;


    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    public void syncBrand(SyncBrandVo syncBrandVo) {
        log.info("syncBrand {}", syncBrandVo);
        try {
            Brand brand = brandRepository.findOne(syncBrandVo.getId());
            if (brand == null) {
                brand = new Brand();
                brand.setId(syncBrandVo.getId());
            }
            CopyUtils.copyProperties(syncBrandVo, brand);
            brand.setStatus(syncBrandVo.getStatus() == 1 ? IStatus.DELETE : IStatus.NORMAL);
            this.saveOrUpdateUsingPo(brandRepository, brandRedisDao, brand, new Brand2BrandRo());
        } catch (Exception e) {
            log.warn("syncBrand warn");
            e.printStackTrace();
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public void syncBrands(List<SyncBrandVo> syncBrandVos) {
        syncBrandVos.forEach(this::syncBrand);
    }

    /**
     * 创建品牌
     * 1.创建品牌Po并设置ID
     * 2.将Vo转换为Po
     * 3.设置品牌的分类
     * 4.持久化品牌并返回
     *
     * @param vo 创建品牌 Vo
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public CreateBrandVo createBrand(final CreateBrandVo vo) {
        // 创建品牌, 并且设置 ID
        final Brand brand = new Brand();
        brand.setId(vo.getId());
        brand.fromVo(vo);
        if (CollectionUtils.isNotEmpty(vo.getCategoryIds())) {
            List<Category> parentCategories = categoryRepository.findByIdInAndDeleteFlag(vo.getCategoryIds(), Boolean.FALSE);
            if (CollectionUtils.isNotEmpty(parentCategories) && parentCategories.size() != vo.getCategoryIds().size()) {
                AssertUtils.notNull(brand, CommodityExceptionType.COMMON_EXCEPTION, "所选分类不存在或被删除");
            }
            brand.setCategories(parentCategories);
        }
        this.saveBrand(brand);
        vo.setId(brand.getId());
        return vo;
    }

    @Transactional(rollbackFor = Exception.class)
    public void updateBrand(final UpdateBrandVo vo) {
        log.info("update Brand vo={}", vo);
        Brand brand = brandRepository.findByIdAndDeleteFlag(vo.getId(), Boolean.FALSE);
        AssertUtils.notNull(brand, CommodityExceptionType.COMMON_EXCEPTION, "被编辑的品牌不存在或者已被删除");
        //移除旧的分类下排序
        List<Long> categoryIds = brand.getCategories().stream().map(Category::getId).collect(Collectors.toList());
        this.delayer.executeAfterTransactionCommit(() -> brandRedisDao.removeAppSort(brand.getId(), categoryIds));
        if (CollectionUtils.isNotEmpty(vo.getCategoryIds())) {
            List<Category> parentCategories = categoryRepository.findByIdInAndDeleteFlag(vo.getCategoryIds(), Boolean.FALSE);
            if (CollectionUtils.isNotEmpty(parentCategories) && parentCategories.size() != vo.getCategoryIds().size()) {
                AssertUtils.notNull(brand, CommodityExceptionType.COMMON_EXCEPTION, "所选分类不存在或被删除");
            }
            brand.setCategories(parentCategories);
        }
        brand.fromVo(vo);
        this.saveBrand(brand);
        log.info("brand after save: {}", brand);
    }


    /**
     * 删除品牌
     * 1.查找品牌
     * 2.设置删除标志
     * 3.持久化
     *
     * @param id 品牌 ID
     * @return
     */
    @Transactional
    public boolean deleteBrand(Long id) {
        Brand brand = brandRepository.findOne(id);
        // 如果需要被删除的品牌不存在, 抛出异常
        AssertUtils.notNull(brand.getId(), CommodityExceptionType.COMMON_EXCEPTION, "被编辑的品牌不存在或者已被删除");
        if (Objects.equals(brand.getDeleteFlag(), Boolean.TRUE)) {
            return Boolean.TRUE;
        }
        brand.setDeleteFlag(Boolean.TRUE);
        this.saveBrand(brand);
        return Boolean.TRUE;
    }


    public SpringPageVO<BrandListItemVo> listBrands(BrandQueryVo brandQueryVo) {
        Page<Brand> brandPage = brandRepository.findAll(new BrandSpecification(brandQueryVo), brandQueryVo.toPageRequest());
        CategoryItemVo categoryItem = new CategoryItemVo();
        if (brandQueryVo.getCategoryId() != null) {
            categoryItem = categoryService.getCategoryItem(brandQueryVo.getCategoryId());

        }
        return SpringPageToSpringPageVO.of(brandPage, new Brand2BrandListItemVo(Optional.ofNullable(categoryItem).orElse(new CategoryItemVo()).getName()));
    }


    /**
     * 获取更新Brand信息
     * 1.查询brand
     * 2.brand transform vo,返回
     *
     * @param brandId
     * @return
     */
    public UpdateBrandVo getUpdateBrandVo(Long brandId) {
        Brand brand = brandRepository.findOne(brandId);
        return new Brand2UpdateBrandVo().apply(brand);
    }

    @Transactional(rollbackFor = Exception.class)
    public void saveOrUpdateSort(BrandSortVo vo) {
        if (vo != null && vo.getBrandSortListVos() != null) {
            List<Long> brandIds = Lists.newArrayList();
            Map<Long, Integer> brandIdAndIdx = new HashMap<>();
            for (BrandSortListVo index : vo.getBrandSortListVos()) {
                brandIds.add(index.getId());
                brandIdAndIdx.put(index.getId(), index.getIdx());
            }
            List<Brand> brands = brandRepository.findAll(brandIds);
            for (Brand brand : brands) {
                brand.setIdx(brandIdAndIdx.get(brand.getId()));
            }
            this.saveBrands(brands);
        }
    }

    /**
     * 查询brand名称信息
     * 1.根据ids返回符合条件的Brand的id与名称信息
     *
     * @param ids
     * @return
     */
    public List<IdNameVo> findBrandByIds(List<Long> ids) {
        return brandList2IdNameList(brandRepository.findByDeleteFlagAndIdIn(Boolean.FALSE, ids));
    }

    private List<IdNameVo> brandList2IdNameList(List<Brand> brandList) {
        List<IdNameVo> resultList = Lists.newArrayList();
        if (CollectionUtils.isNotEmpty(brandList)) {
            for (Brand index : brandList) {
                resultList.add(new IdNameVo(String.valueOf(index.getId()), index.getName()));
            }
        }
        return resultList;
    }

    /**
     * 通过品牌名称分页查找品牌IdNameVo
     * 1.根据查询条件查找分页Brnad
     * 2.将listBrand转换为ListIdName
     * 3.返回分页
     *
     * @param searchPageVo
     * @return
     */
    public SpringPageVO<IdNameVo> findBrandsByName(SearchPageVo searchPageVo) {
        Page<Brand> pageBrands = brandRepository.findByNameLikeAndDeleteFlag("%" + searchPageVo.getSearchValue() + "%",
                Boolean.FALSE, new PageRequest(searchPageVo.getPageIndex(), searchPageVo.getPageSize()));
        List<IdNameVo> resultList = brandList2IdNameList(pageBrands.getContent());
        return new SpringPageVO<IdNameVo>(resultList, pageBrands.getTotalElements(), searchPageVo.getPageSize(), searchPageVo.getPageIndex());
    }

    /**
     * 后台使用  通过分类获取品牌
     * @param categoryId
     * @return
     */
    public List<IdNameVo> listBrandByCategory(Long categoryId) {
        List<Brand> brands = brandRepository.findBycategoryIdAndDeleteFlag(categoryId, Boolean.FALSE);
        return Lists.transform(brands, new Brand2IdNameVo());
    }

    /**
     * 获取当前分类下的所有子分类set
     *
     * @param category
     * @return
     */
    Set<Category> getAllChildCategory(Category category) {
        Set<Category> categorySet = Sets.newHashSet();
        if (CollectionUtils.isEmpty(category.getChildren()) && category.getDeleteFlag() == Boolean.TRUE) {
            return categorySet;
        }
        for (Category index : category.getChildren()) {
            categorySet.add(index);
            if (CollectionUtils.isNotEmpty(index.getChildren())) {
                categorySet.addAll(getAllChildCategory(index));
            }
        }
        return categorySet;
    }

    /**
     * 获取当前分类和当前分类子分类的所有品牌
     * 1.判断分类下的品牌是否为空
     * 2.遍历品牌集合剔除不符合要求的品牌
     * 3.遍历子分类并递归调用原方法,获取所有符合条件的品牌
     *
     * @param category     分类
     * @param searchValue  搜索值
     * @param searchPageVo
     * @return 品牌列表页列表项集合
     */
    private Page<Brand> buildCategoryNotDeleteBrandsCascadeChildren(Category category, String searchValue, SearchPageVo searchPageVo) {
        List<BrandListItemVo> vos = Lists.newArrayList();
        log.debug("获取选中分类的子分类");
        Set<Category> categorySet = getAllChildCategory(category);
        categorySet.add(category);
        List<Long> categoryIds = Lists.newArrayList();
        for (Category index : categorySet) {
            categoryIds.add(index.getId());
        }
        log.debug("需要查询的分类ID集合[{}]");
        Page<Brand> brands = brandRepository.findByCategoriesIdInAndNameLikeAndDeleteFlag(categoryIds,
                "%" + searchValue + "%", Boolean.FALSE,
                new PageRequest(searchPageVo.getPageIndex() - 1, searchPageVo.getPageSize()));
        return brands;
    }

    /**
     * 所有未禁用的品牌
     */
    public List<IdNameVo> findAll() {
        List<Brand> brands = brandRepository.findAll();
        List<IdNameVo> resultVos = Lists.newArrayList();
        for (int i = 0, len = brands.size(); i < len; ++i) {
            if (brands.get(i).getStatus() == IStatus.NORMAL) {
                IdNameVo vo = new IdNameVo(brands.get(i).getId() + "", brands.get(i).getName());
                resultVos.add(vo);
            }
        }
        return resultVos;
    }

    /**
     * 前端通过分类Id或取对应的品牌
     *
     * @param categoryId
     * @return
     */
    public List<IdNameVo> listBrandByCategoryId(Long categoryId) {
        List<BrandRo> brandRos = brandRedisDao.getAppBrand(categoryId);
        List<IdNameVo> respVos = Lists.newArrayList();
        brandRos.stream().filter(Objects::nonNull).forEach((p) -> {
            respVos.add(new IdNameVo(String.valueOf(p.getId()), p.getName()));
        });
        return respVos;
    }
}
